  // NodeID : ID des Empfängers
  
  #define NODEID 42
  #define BASEID 41
  // mit der 6 war chronloc
  #define BASEADR 0x12345700
  
  #define ISDONGLE 1
  
//  #define SIMULATE 
  /*
  Messungen Stromverbrauch Release 3. Mai 2013
  auf "Mini" Board
  Gemessen mit Oszi Parallel zu BAT85
  Dann mit Widerstand verglichen:
  Vollbetrieb 150 Ohm
  Ohne Radio ca 470 Ohm 
  PM2 150 kOhm 
  Bei 3 Volt Vcc
  -> 20/6 mA, 20 uA
  OSZI 5 mV/DIV
  */
  
  // Wert fuer Timeout, der einer Millisekunde in cc1110 RX TIO entspricht
  #define TIO_1MSEC 183


  #include <stdio.h>
  #include <string.h>

//  #include "hal.h"
  #include "RF04EB.h"
  #include "cc_radio.h"
  #include "myglobals.h"
  //#include "us.h"
  #include "display.h"
  #include "mycc1110radio.h"


  // Dongle ist am PC, MODULE am TCON Display
  #define P_DONGLE 3
  #define P_MODULE 4
  
  #define MSGTYPE_LINE0 0
  #define MSGTYPE_LINE1 1
  
  #define MSGTYPE_CALL 2
  #define MSGTYPE_OK 3
  #define MSGTYPE_HUP 4
  #define MSGTYPE_CRCERR 5
  #define MSGTYPE_REMOTEBOOT 5

  // Definitionen für TCOn Bpard

  #define  TCON_RESET P0_7 //Ausgang
  #define  TCON_BUSY  P0_6
  #define  TCON_SO P0_0
  #define  TCON_SI P0_1   //Ausgang
  #define  TCON_SCLK P0_5 //Ausgang
  #define  TCON_CS P0_4   //Ausgang

  // http://blog.gmane.org/gmane.comp.compilers.sdcc.user/month=20070201/page=6
  //#define TCON_OMASKE 0%10110010
  #define TCON_OMASKE 0xB2

  extern volatile BITVAR rx_newSFD; // neues Paket wird empfangen 
  extern UINT8 rx_len; // Laenge des neuen Pakets
  extern volatile mytime32 rx_sfdtime;
  extern volatile UINT8 tx_idle; // UART TX
  extern volatile UINT16 sio_rx_len;
 
  volatile mytime32 sfdtime_ms;
  volatile mytime32 lastSyncTime;
  volatile mytime32 timeUS;
  //volatile mytime32 test;
  UINT8 plen, lqi;
  
  UINT16 timediff; // Hilfsvariable für Zeit seit letzem RFD
  UINT16 senddelaytics; 
  UINT8 theTxBuf[150];
  UINT8 theRxBuf[150];
  UINT8 theblockbuf[BYTES_P_LINE * LINES_P_BLOCK ]; // Puffer zum Speichern der Blockdaten

  extern volatile UINT8 timer3Interrupt;
  extern volatile UINT8 sio_rx_has_line; 
  extern UINT8 theSioInpLine[SIO_INBUFLEN];

  UINT8 RXcallBackFunction(void); 
  void dumpPacket(void);
  void prhex(unsigned char x);
  UINT8 dongle_open(void);
  UINT8 PROGMODE;
  sim_frame *simrx, *simtx;
  UINT32 myadr, otheradr;
  UINT8 tempu8;
  UINT8 balt, bneu;
  char c;
  UINT8 timertic; // fuer sleep mode
  UINT8 sleep_mod; 
  UINT8 breaks_in_mod;
  // forward
  void go_pm2(void);

  UINT16 zeile; 
  UINT8 pixelbyte_nr;

  void  tcon_send_byte(UINT8 b);
  void  tcon_busywait(void); 
  void tcon_init();
  void tcon_writeline(char* buf);
  void tcon_dispupd();
  void tcon_off();
  
    
  
  void main(void)
  {

    static UINT8 i;
    static volatile UINT16 i16;
    static UINT8 errcnt;
    static UINT8 rxerrcnt;
    long blinx;
    static UINT8 flipper;
    static UINT16 rxlinenr;
//    UINT8 plen;
 //   UINT32 q;
    
  //  myadr = 0x10345678;
    if (ISDONGLE) {
	  PROGMODE =  P_DONGLE;
	  myadr = BASEADR  | BASEID;
	  otheradr  = BASEADR | NODEID;
	  }
    else {
          PROGMODE =  P_MODULE;
	  otheradr = BASEADR | BASEID;
	  myadr  = BASEADR | NODEID;
	}


    simrx = (void*) theRxBuf;
    simtx = (void*) theTxBuf;
   
    SET_32KHZ_CLOCK_SOURCE(CRYSTAL);
    SET_MAIN_CLOCK_SOURCE(CRYSTAL);
    CLKCON &= 0x00;    
     
    INIT_GLED();
    SET_GLED();
    init_uart(SIO_BAUD);
    mydelayms(10);
    INT_GLOBAL_ENABLE(INT_ON);
    c = U0DBUF; // toggle receiver

    printf("BUILT %s %s \n" , __TIME__ , __DATE__);
    printf("NODEID %d \n" , NODEID);
    if (PROGMODE == P_DONGLE) printf("PROGMODE P_DONLGE\n");
    if (PROGMODE == P_MODULE) printf("PROGMODE P_MODULE\n");
    
    lastSyncTime.t32 = currtime32();
    mydelayms(50);
    lastSyncTime.t32 = currtime32() - lastSyncTime.t32;
    timeUS.t32 = lastSyncTime.t32 * 30 + (lastSyncTime.t32 >> 1);
    printf("TIME 50000 usec: %ld \n", timeUS.t32);
      
    


    mydelayms(300);
    INT_GLOBAL_ENABLE(INT_OFF);   
      
    // Sleep Timer auf 15 Bit einstellen
    WOREVT1 = 0x80;
    WOREVT0 = 0x00;
    mydelayus(100);
    WORCTRL = 0x74;
    mydelayus(100);
    
    INT_GLOBAL_ENABLE(INT_ON); 
  //  c = U0DBUF; // toggle receiver
      
    blinx = 0; 
    initcc1110();

//    setRxTIO(100000);
    setRxTIO(10 * TIO_1MSEC);
// 6000 scheinen wohl ca. 30-40 msec zu sein also ca 200 fuer 1msec
// gemessen 10'000 TIO sind 55,4 msec
// 1 msec sind ca 184 TIOS
    RFST = SRX; 
    timediff = currtime16();
    plen = readcc1110Packet(theRxBuf);
    RFST = SIDLE; // strom sparen
    timediff = currtime16() - timediff;
    timediff &= 0x7fff;
    timediff = timediff * 30 + (timediff >> 1);
    printf("RXTIME TIOVAL 10 TIO_1MSEC %d\n", timediff);
    
    sleep_mod = 1; timertic = 0; breaks_in_mod = 0; errcnt = 0;// kurze Schlafphase
    i=0;

  // Hauptschleife
  sio_rx_has_line = 0;
  setRxTIO( 30 * TIO_1MSEC);
     errcnt = 0;
     
  for(;;) {
    
  if (PROGMODE == P_MODULE) {
      GLED = !GLED; // Neues Board invertiert GLED
      setRxTIO( 30 * TIO_1MSEC);
      RFST = SRX;
      plen = readcc1110Packet(theRxBuf);
      RFST = SIDLE; // strom sparen
      if (plen > 0) printf("#Received something\n");
      if ( (plen > 0)  && (simrx->qadr == otheradr) && (simrx->zadr == myadr) 
	      && (simrx->typ == MSGTYPE_CALL) )  {
	printf("#got call\n");
	// send 2 OKs 

	tcon_init();
	
	simtx->cc_len = 10;
	simtx->qadr = myadr;
	simtx->zadr = otheradr;
	simtx->typ = MSGTYPE_OK;
	
	plen = sendcc1110Packet(&theTxBuf[1], theTxBuf[0], 1); // keep RX on
/*	mydelayms(5);
	plen = sendcc1110Packet(&theTxBuf[1], theTxBuf[0], 1); // keep RX on
*/

	// now reading data
	// still having 30 msec TIO
	rxlinenr = 0; flipper = 0;
	plen = 1;
	while (rxlinenr < (LINES_P_BLOCK * BLOCKS_P_SCREEN ))  {
	  rxerrcnt = 0;
	  setRxTIO( 100 * TIO_1MSEC); // 100 Msec Wartezeit, sollte für Dongle-Resend reichen
	  while (plen == 0)  {
	     printf("#err got PLEN 0\n");
	     rxerrcnt++;
	     if (rxerrcnt > 3) break;
	     plen = readcc1110Packet(theRxBuf);
	     }
	  
	  lqi = 0;
	  if (plen > 0) lqi = theRxBuf[plen-1];
	  printf("#got plen %d msg %d lqi %d\n", plen, simrx->typ, lqi);
	  // check integrity of packet
// silently discard if resend 
// send ack
	  if (  (plen = 141) && (simrx->qadr == otheradr) && (simrx->zadr == myadr) ) {
		if (lqi & 0x80)  if (simrx->typ == flipper) {
		      // hier paket ausgeben
		      tcon_writeline(&theRxBuf[10]);
		      printf("line %d OK\n", rxlinenr);
		      rxlinenr++; flipper ^= 1;
		  }; // gutes paket bekommen

// send ack
	        simtx->typ = (lqi & 0x80 ? MSGTYPE_OK : MSGTYPE_CRCERR); 
		mydelayms(1);
		plen = sendcc1110Packet(&theTxBuf[1], theTxBuf[0], 1); // keep RX on
		printf("Sent ACK %d\n", simtx->typ);
	     } 
//	  printf("#l %d %d %d \n", plen, rxlinenr, theRxBuf[plen-1]);
	  } // while RxLineNr

	  if (rxerrcnt <= 3) {
	   printf("#Reception completet OK!\n");
	   tcon_dispupd();
	   printf("#Display updated and off OK!\n");
   	   tcon_off();
	  }
	  
	else { printf("#Bulk transfer error ERR!\n");
	   tcon_off();
	}
      };
      if (errcnt < 50) errcnt++;
      else go_pm2();
    };

  // Ende Hauptschleife 
  if (PROGMODE == P_DONGLE) {
    for (;;) {
      if (sio_rx_has_line) {
	printf("# -> %s\n" , theSioInpLine);
	sio_rx_has_line = 0;
        
        if (theSioInpLine[0] == 'O') {
	    printf("RING\n");
            if (dongle_open() == 0) printf("CLOSED\n");	    
	    }
	}  
      mydelayms(10);
      blinx++;
      if (!(blinx & 0x0f))   GLED = !GLED;
      if (blinx > 100) { 
	  printf("IDLE\n");
	  blinx = 0;
	  }
      } // for 
    } // P_Dongle
  } // for MAIN LOOP 

  } // main

  UINT8 RXcallBackFunction(void)
  {
  //zero value indicates that the contents of both memory blocks are equal.
  if (rx_len > 0)
    {
      sfdtime_ms.t32 = rx_sfdtime.t32;
      sfdtime_ms.t32 *= 100L;
      sfdtime_ms.t32 >>= 7;
      sfdtime_ms.t32 *= 100L;
      sfdtime_ms.t32 >>= 8;
      return(TRUE);
    }
  return (FALSE);
  }

  void prhex(unsigned char x)
  {
  //printf("0x");
  putchar( (x >> 4) >= 10 ? (x >> 4) + 0x41-10 : (x >> 4) | 0x30 );
  putchar( (x & 0x0f) >= 10 ? (x &0x0f) + 0x41-10 : (x & 0x0f) |  0x30 );
  putchar(' ');
  }

  void dumpPacket(void)
  {
  BYTE myRssi, myLqi, i;

  UINT8 *p = theRxBuf;

  if (0 == 1) {
    printf("RX "); 
    putbyte((rx_len+3) | 0x80); // binaermodus laengentoken
    putbyte(rx_len); putbyte(theRxBuf[rx_len]); putbyte(theRxBuf[rx_len+1]); 
    for(i=0; i<(rx_len); i++) putbyte(*p++);
    }
  else {
    
    printf("RX t%ld l%d ", sfdtime_ms.t32, rx_len);
    for(i=0; i<(rx_len); i++) prhex(*p++);
    myRssi = *p++;
    myLqi = *p++;
    putchar('r');prhex(myRssi);
    putchar('q');prhex(myLqi);
    }
    printf("\n");

    // Last two bytes contain RSSI level and Correlation value in addition to CRC OK.
    // Checking that the CRC value is OK
  //   sfdtime = (void*) &ReceiveData.sfdt0;
  //   printf("SFD %ld Delta %ld ", *sfdtime, *sfdtime - lastsfd);
  //   if(myLqi & 0x80) printf("crc OK \n");
  //   else printf("crc *ERR* \n");


  }



  /******************************************************************************
  Interrupt for TIMER3PERIODUS (value set in global.h) timer 3

  3 * 600 us = 1.8 ms => this is the time we have to wait after a wake up
  until the us signal is sent.
  ******************************************************************************/

  void T3_IRQ(void) __interrupt(T3_VECTOR) {
    
      INT_SETFLAG(INUM_T3, INT_CLR);
      timer3Interrupt++;
      // after 3 * TIMER3PERIODUS stop the timer
      if(timer3Interrupt >=3) 
      {
	  TIMER3_RUN(FALSE);  // stop timer3
      }
  }

  /*
  ******************************************************************************
  Interrupt for wake up from sleep timer
  ***************************************************************************** */

  // #pragma vector=ST_VECTOR
  void powermodes_ST_IRQ(void) __interrupt (ST_VECTOR) {
    INT_SETFLAG(INUM_ST, INT_CLR);
  //   timertic++;
  }

  void go_pm2(void) {
	while (!tx_idle) ; // UART noch ausschreiben
	mydelayus(200);	 // noch 2 Zeichen rauslassen
	INT_GLOBAL_ENABLE(INT_OFF);
	GLED= 0;
	
	// Timer Interrupt erlauben
  // alle anderen Interrupts aus
	  IEN0 = 0; IEN1=0; IEN2 = 0;
  //	INT_GLOBAL_ENABLE(FALSE);
  // alle IRQs löschen ausser timer
  //	if ((!LED_NOBLINK) && USELED) { CLR_GLED(); CLR_YLED(); };
	  P0SEL=0;P0DIR=0; P0INP=0;
	  P1SEL=0;P1DIR=0; P1INP=0;
	  P2SEL=0;P2DIR=0; P2INP=0;
	  U0CSR=0; // UART aus
	  U1CSR=0; // UART aus       
	
	WORCTRL = 0x74;
	mydelayus(100);
	WORIRQ = 0;
	WORIRQ = 0x10;           
	
	  INT_SETFLAG(INUM_ST, INT_CLR);
	  INT_ENABLE(INUM_ST, INT_ON);
	  INT_GLOBAL_ENABLE(TRUE);	      
  // Alignment of entering PM{0 – 2} to a positive edge on the 32 kHz clock source
  // inner sleep loop
  for(;;) {	
	
	bneu  = (WORTIME0 & 0x01);
	balt = bneu;
	while( balt | !bneu) {
	      balt = bneu;
	      bneu  = (WORTIME0 & 0x01);
	      };	// Wait until a positive 32 kHz edge 
	  SLEEP |= 2; // Sleep Mode is PM2
	  PCON |= 0x01;	// Enter PM{0 – 2}	
  // hier noch NOPS
	_asm
	  nop
	  nop
	  nop
	_endasm;
	timertic++;
	if (timertic >= sleep_mod) { // Dynamische Zeitverlaengerung
	  timertic =0;
	  breaks_in_mod++;
	  if ((sleep_mod==2) && (breaks_in_mod >=10)) {
	      sleep_mod=5;
	      breaks_in_mod=0;
	    }
	  if ((sleep_mod==1) && (breaks_in_mod >=10)) {
	      sleep_mod=2;
	      breaks_in_mod=0;
	    }
	  break;	
	  } // Modulo Event
	} // inner sleep loop
	
	INIT_GLED();
  //  INIT_YLED();
    //     SET_GLED();
	WORIRQ = 0;
	GLED = 0; // wird bei rx auf 1 gesetzt
	  INT_ENABLE(INUM_ST, INT_OFF);
	  INT_SETFLAG(INUM_ST, INT_CLR);
	INT_GLOBAL_ENABLE(INT_ON);   
	SET_MAIN_CLOCK_SOURCE(CRYSTAL);
	  CLKCON &= 0x00;    
	init_uart(SIO_BAUD);
	  c = U0DBUF; // toggle receiver
	initcc1110();
  //       printf("BrkMod %d\n" , breaks_in_mod);
  }

  void  tcon_send_byte(UINT8 b) {
  UINT8 sbi;
  for(sbi = 8;sbi>0;sbi--) {
      if (b & 0x01 ) TCON_SI = 1;
	  else TCON_SI = 0;
      TCON_SCLK = 1;
      b >>= 1;
      TCON_SCLK = 0;
  }
  }
  
  void  tcon_busywait(void) {
    while (TCON_BUSY) ;
  }
  
  void tcon_init() {

    TCON_CS = 0;                     // Chip Select get low
    TCON_RESET = 0;                  // RESET get low
    TCON_SI = 0;
    TCON_SCLK = 0;
    P0DIR = TCON_OMASKE;              // Ausgänge aktivieren  

    mydelayms(10);                      // T_VCC_ON > 10 ms

  //Reset Display TCON
    TCON_CS = 1;                     // Chip Select get high
    TCON_RESET = 1;                  // RESET bzw. ON  get high (POWER)
    mydelayms(120);                    // Ton_cs
    TCON_CS  = 0;                  // RESET get low
    mydelayms(1);                    //   Tcs_si
  // Jetzt Header schreiben
    tcon_send_byte(0x06);
    tcon_send_byte(0xa0);
    tcon_busywait();
}

void tcon_writeline(char* buf) {
UINT8 pcnt;
	tcon_busywait();	
	for(pcnt=128; pcnt != 0; pcnt--) {
	    tcon_send_byte(*buf++);
	} // pixelbyte
}    

void tcon_dispupd() {
 
    printf("#UPD1\n");
    tcon_busywait();
    
    TCON_SI = 0;
    TCON_SCLK = 0;
    TCON_CS = 1;                     // Display Update
    
    mydelayms(200);

    printf("#UPD2\n");
    tcon_busywait();

    printf("#UPD3\n");
    tcon_off();
    }

void tcon_off() {

    TCON_CS = 0;                     // Chip Select get low
    TCON_RESET = 0;                  // Vcc abschalten
    mydelayms(200);
    }
    
  
  UINT8 dongle_connect(void) {
  // 11 Sekunden lang ca. alle 30 usec ein Paket senden und auf Antwort warten
  UINT8 sec;
  UINT8 persec;
  RFST = SIDLE; // muss hier sein um empfangenes Paket zu leeren ??
  setRxTIO(20 * TIO_1MSEC); // ca20msec timeout
  sec = 12;
      simtx->cc_len = 10;
      simtx->qadr = myadr;
      simtx->zadr = otheradr;
      simtx->typ = MSGTYPE_CALL;
      while(sec > 0) {
	 for(persec = 0;persec < 50; persec++) {
	    plen = sendcc1110Packet(&theTxBuf[1], theTxBuf[0], 1); // keep RX on
	    plen = readcc1110Packet(theRxBuf);
	    if ( (plen > 0)  && (simrx->qadr == otheradr) && (simrx->zadr == myadr) ) 
		  { // anhderes Paket empfangen
		    if (simrx->typ == MSGTYPE_OK) {
		      printf("#Connect OK\n");
		      printf("CONNECT\n");
		      mydelayms(20);
		      return 0;
		    }
		  }
	    } // persec
      sec--;
      printf("#Remaining %d secs \n", sec);
      printf("RING\n");
      } // sec > 0
      printf("#Connect Timeout\n");
      printf("TIO\n");
      return -1;
  }


  UINT8 dongle_open(void) {
      static UINT8 blocknr;
      static UINT8 linenr;
      static UINT8 res;
      UINT8 retry;
//      UINT8* ptr;
      printf("#open requested\n");
      res = dongle_connect();
      printf("#Result connect: %d \n", res);
      // pretend open was successful
      if (res != 0) return res;
//      printf("OK\n"); // OK kam schon
      // prepare TXBUF
      RFST = SIDLE; // muss hier sein um empfangenes Paket zu leeren ??
      simtx->cc_len = 10+BYTES_P_LINE;
//      simtx->cc_len = 20;
       setRxTIO(20 * TIO_1MSEC); // ca20msec timeout
      // read in n Blocks    
      for(blocknr = 0;blocknr < BLOCKS_P_SCREEN; blocknr++) {
        for(linenr = 0;linenr < LINES_P_BLOCK; linenr++) {
            printf("#W %d\n", blocknr * LINES_P_BLOCK + linenr);
#ifndef SIMULATE
	           while(!sio_rx_has_line) ;
#endif
#ifdef	SIMULATE
	    sio_rx_len = 129;
	    theSioInpLine[0] = 'L';
	    for(res = 0;res< 128;res++) theSioInpLine[res+1] = res;
	    sio_rx_has_line = 1;
#endif
	    if ((sio_rx_len != BYTES_P_LINE+1) || (theSioInpLine[0] != 'L')) {
                    printf("#%s line %d %s block %d line %d\n", __FILE__, __LINE__, "type/len faulty", blocknr, linenr);
                    printf("FAILED\n");
                    sio_rx_has_line = 0;
		    return 1;
                    } // if len
            
            memcpy(&theTxBuf[10] , &theSioInpLine[1], BYTES_P_LINE);
	    sio_rx_has_line = 0;
	    if (linenr < LINES_P_BLOCK-1) printf("OK\n");
// now already receiving serial data	   
	      simtx->typ = (linenr & 1 ? MSGTYPE_LINE1 : MSGTYPE_LINE0);
	      res = -1;
	      for(retry = 0; retry < 4; retry++) {
		if (retry > 0) mydelayms(2);
		plen = sendcc1110Packet(&theTxBuf[1], theTxBuf[0], 1); // keep RX on
//		lqi = 0x80;
		plen = readcc1110Packet(theRxBuf);
//		if (plen > 0) lqi = theRxBuf[plen-1];
		if ( (plen >=10)  && (simrx->qadr == otheradr) && (simrx->zadr == myadr) && (simrx->typ == MSGTYPE_OK) 
		    /* && !(lqi & 0x80) */) {
		  res = 0;
		  break;
		  }
		 printf("#Retry %d failed!\n", retry);
	      } // FOR RETRY
	    if (res != 0) { printf("#Hang up\n"); printf("FAILED\n"); return 1;}  
	    printf("#L: %d\n", plen);
// hoping that sending is not to fast ....
        } // for linenr
        // jetzt Block OK senden ...
	printf("OK\n");
     } // for blocknr 
     printf("#image transmission completed\n");
     printf("COMPLETE\n");
     return 0;
  }
  
  
  /*
  * Eingänge/ Ausgänge aus Sicht cc1110
  * 
  * P0.7 reset: Ausgang 
  * P0.6 Busy: Eingang 
  * P0.0 SO: Eingang: 1 bedeutret Display arbeitet 
  * P0.1 SI
  * P0.5 SCLK: Ausgang 
  * P0.4 CS: Ausgang
  * 
  */

